﻿namespace QdArch
{
    public class StairAction3D :Element3DAction
    {
        public static StairAction3D Instance=new StairAction3D();

        public override LightCAD.Three.BufferGeometry[] CreateGeometry3D(LcLevel level, LcElement element, Matrix3 matrix)
        {
            var stair = element as QdStairRef;
            var laddergeo = CreateLadder(stair.StepHeight, stair.StepNum, stair.StepWidth, stair.LadderWidth, stair.SlabThickness);
            var laddergeo2 = laddergeo.clone()
                .rotateZ(-MathUtil.Pi)
                .translateQuick(stair.PlatLen, stair.StepNum * stair.StepWidth, stair.StepNum * stair.StepHeight);

            var plat = CreatePlat(stair.PlatLen, stair.PlatWidth, stair.PlatThickness);
            plat.translateQuick(0, stair.StepNum * stair.StepWidth, stair.StepNum * stair.StepHeight);
            var plat2 = CreatePlat(stair.PlatLen, stair.PlatWidth, stair.PlatThickness);
            plat2.translateQuick(0, -stair.PlatWidth, 0);
            var plat3 = plat2.clone().translateQuick(0, 0, stair.StepNum * stair.StepHeight * 2);
            var result = new BufferGeometry[] { laddergeo, laddergeo2, plat, plat2, plat3 };
            matrix = matrix * stair.Matrix;
            foreach (var geo in result)
            {
                GeoUtil.GeoApplyMatrix3d(geo, matrix);
                geo.computeVertexNormals();
            }
            return result;
        }
        private LightCAD.Three.BufferGeometry CreateLadder(double stepHeight, int stepNum, double stepWidth, double ladderLen, double slabThickness)
        {
            var poly = new ListEx<Vector2>();
            for (int i = 0; i < stepNum; i++)
            {
                var x = i * stepWidth;
                var y = i * stepHeight;
                poly.Push(new Vector2(x, y), new Vector2(x, y + stepHeight));
            }
            poly.Push(new Vector2(stepNum * stepWidth, stepNum * stepHeight));
            var p0 = poly[0];
            var p2 = poly[2];
            var obliqueDir = p2.Clone().Sub(p0).Normalize();
            var offsetDir = obliqueDir.Clone().RotateAround(new Vector2(), -Math.PI / 2);
            var sp = new Vector2().AddScaledVector(offsetDir, slabThickness);
            sp = CurveUtil.LineIntersectLine2D(sp, obliqueDir, p0, new Vector2(1, 0));
            var ep = CurveUtil.LineIntersectLine2D(sp, obliqueDir, poly.Last(), new Vector2(0, -1));
            poly.Push(ep, sp);
            poly.Reverse();
            var shape = new LightCAD.Three.Shape(poly);
            var coodMat = new Matrix4();
            coodMat.MakeBasis(new Vector3(0, 1, 0), new Vector3(0, 0, 1), new Vector3(1, 0, 0));
            return GeoUtil.GetStretchGeometryData(shape, coodMat, ladderLen, 0).GetBufferGeometry();
        }

        private LightCAD.Three.BufferGeometry CreatePlat(double len, double width, double thickness)
        {
            var shape = ShapeUtil.Rect(0, 0, len, width);
            var coodMat = new Matrix4();
            coodMat.MakeBasis(new Vector3(1, 0, 0), new Vector3(0, 1, 0), new Vector3(0, 0, 1));
            return GeoUtil.GetStretchGeometryData(shape, coodMat, 0, -thickness).GetBufferGeometry();
        }
    }
}
